#light


module CGraph.DataTransactionGlue

open CGraph.Transactions
open CGraph.DG2
open CGraph.DataModel
open CGraph.Generic.Impl
open CGraph.Generic
open CGraph.DataGraph
open CGraph.DataSchema
open System

let AddOrRemove item (list:'a System.Collections.Generic.List) (idx:int) = 
    match idx with
        | -1 -> list.Remove item |> ignore
        | _ -> 
            let idx = min idx list.Count
            list.Insert(idx,item)
        
    
type VertexAction( m_data:DirectedGraphData, vtx:VertexHandle, oldIdx:int, newIdx:int ) =
    inherit PropertyAction<VertexHandle,int>(vtx,oldIdx,newIdx,
        PASetter<VertexHandle,int>( fun hdl idx -> AddOrRemove vtx m_data.Vertexes idx )
        , "VertexHandle" )
                
    interface IDisposable with
        member s.Dispose() =
            m_data.HandleSystem.RemoveReference vtx.Handle (fun hdl -> m_data.Vertexes.Contains vtx)
            GC.SuppressFinalize s
            
            
let CreateVertexAction (m_data:DirectedGraphData) (vtx:VertexHandle) (oldIdx:int) (newIdx:int) = 
    m_data.HandleSystem.AddReference vtx.Handle
    new VertexAction(m_data,vtx,oldIdx,newIdx)
    
type EdgeAction(m_data:DirectedGraphData, edge:EdgeHandle, oldInc:int, oldOut:int, newInc:int, newOut:int) =
    inherit PropertyAction<EdgeHandle,int*int>(edge,(oldInc,oldOut),(newInc,newOut),
        PASetter<EdgeHandle,int*int>( fun hdl (incIdx,outIdx) ->
            let realEdge = m_data.HandleSystem.FromHandle hdl
            let realInc = m_data.HandleSystem.FromHandle realEdge.IncomingVertex
            let realOut = m_data.HandleSystem.FromHandle realEdge.OutgoingVertex
            AddOrRemove hdl realInc.OutEdgeList outIdx
            AddOrRemove hdl realOut.IncEdgeList incIdx), "EdgeAction" )
            
    interface IDisposable with
        member s.Dispose() =
            m_data.HandleSystem.RemoveReference edge.Handle (fun hdl ->
                let realEdge = m_data.HandleSystem.FromHandle edge
                let incVert = m_data.HandleSystem.FromHandle realEdge.IncomingVertex
                let outVert = m_data.HandleSystem.FromHandle realEdge.OutgoingVertex
                (incVert.OutEdgeList.Contains edge) && (outVert.IncEdgeList.Contains edge) )
                
            GC.SuppressFinalize s
            
            
let CreateEdgeAction (m_data:DirectedGraphData) (edge:EdgeHandle) (oldInc:int) (oldOut:int) (newInc:int) (newOut:int) = 
    m_data.HandleSystem.AddReference edge.Handle
    new EdgeAction(m_data,edge,oldInc,oldOut,newInc,newOut)
    
           
type GraphDataBindCallbacks = { VertexAdded:VertexCallback; VertexRemoved:VertexCallback; 
    EdgeAdded:CGraph.DG2.EdgeCallback; EdgeRemoved:CGraph.DG2.EdgeCallback }
           
let BindGraph (data:DirectedGraphData) (transSystem:TransactionSystem) =
    let ConditionalCall = transSystem.AddAction
    let negOne = -1
    let vadd (vtx:VertexHandle) (idx:int) = 
        ConditionalCall <| fun() -> (CreateVertexAction data vtx negOne idx) :> IAction
    let vrem (vtx:VertexHandle) (idx:int) = 
        ConditionalCall <| fun() -> (CreateVertexAction data vtx idx negOne) :> IAction
    let eadd (edge:EdgeHandle) (incIdx:int) (outIdx:int) = 
        ConditionalCall <| fun() -> (CreateEdgeAction data edge negOne negOne incIdx outIdx ) :> IAction
    let erem (edge:EdgeHandle) (incIdx:int) (outIdx:int) = 
        ConditionalCall <| fun() -> (CreateEdgeAction data edge incIdx outIdx negOne negOne ) :> IAction
    { VertexAdded=VertexCallback(vadd);
      VertexRemoved=VertexCallback(vrem);
      EdgeAdded=CGraph.DG2.EdgeCallback(eadd);
      EdgeRemoved=CGraph.DG2.EdgeCallback(erem) }
      
type DataModelAddRemoveAction(store:DataModelData,oldVal:bool,newVal:bool,m_handle:DataModelDataEntryHandle,m_value:DataModelDataEntry) =
    inherit PropertyAction<DataModelDataEntryHandle,bool>(m_handle,oldVal,newVal,
        PASetter<DataModelDataEntryHandle,bool>( fun hdl valid ->
            if valid 
                then store.HandleSystem.StoreObject hdl.Handle (m_value:>obj)
                else store.HandleSystem.RemoveObject hdl.Handle ), "DataModelAddRemoveAction" )
                

type DataModelDataChangeAction(store:DataModelData,hdl:DataModelDataEntryHandle,oldVal:obj,newVal:obj) =
    inherit PropertyAction<DataModelDataEntryHandle,obj>(hdl,oldVal,newVal,
        PASetter<DataModelDataEntryHandle,obj>( fun hdl data ->
            let entry = store.HandleSystem.HandleIndex.Items.[hdl.Handle]
            let dataEntry = entry.Object :?> DataModelDataEntry
            dataEntry.Value <- data ), "DataModelAddRemoveAction" )
            
(*
type OnDataTypeCreate = delegate of name:DataModelDataEntryHandle*value:obj->unit
type OnPropertySet = delegate of handle:DataModelDataEntryHandle*oldValue:obj*newValue:obj->unit
type OnPropertyRemove = delegate of handle:DataModelDataEntryHandle*data:obj->unit *)
type DataModelBindCallbacks = { Create:OnDataTypeCreate; Set:OnPropertySet; Remove:OnPropertyRemove }

let BindDataModel (store:DataModelData) (transSystem:TransactionSystem) =
    let ConditionalCall = transSystem.AddAction 
          
    let onc (name:DataModelDataEntryHandle) (item:DataModelDataEntry) =
        ConditionalCall <| fun() -> DataModelAddRemoveAction(store,false,true,name,item) :> IAction
    let onr (name:DataModelDataEntryHandle) (item:DataModelDataEntry) =
        ConditionalCall <| fun() -> DataModelAddRemoveAction(store,true,false,name,item) :> IAction
    let ons (name:DataModelDataEntryHandle) (oldv:obj) (newv:obj) =
        ConditionalCall <| fun() -> DataModelDataChangeAction(store,name,oldv,newv) :> IAction
    { Create=OnDataTypeCreate(onc);Remove=OnPropertyRemove(onr);Set=OnPropertySet(ons) }

let CreateCallbackEventGraph (graph:IDirectedGraph) (backingStore:DirectedGraphData) (cbacks:GraphDataBindCallbacks)  =
    CreateEventGraph graph backingStore cbacks.EdgeAdded cbacks.EdgeRemoved cbacks.VertexAdded cbacks.VertexRemoved
    
let CreateDataGraphTransactionInterfaces ((data:GraphDatabaseData),(transSystem:TransactionSystem),(dbase:GraphDatabase)) =
    let graphCallbacks = BindGraph data.Graph.BackingStore transSystem
    let schemaCallbacks = BindGraph data.Schema.BackingStore transSystem
    let dataCallbacks = BindDataModel data.Data transSystem
    let schemaGraph = CreateCallbackEventGraph data.Schema.Graph data.Schema.BackingStore schemaCallbacks
    let model = CreateEventDataModel (data.Data,dataCallbacks.Create,dataCallbacks.Set,dataCallbacks.Remove)
    let dataGraph = CreateCallbackEventGraph data.Graph.Graph data.Graph.BackingStore graphCallbacks
    let schema = CreateISchemaGraph { data.Schema with Graph=schemaGraph; Data=model }
    let graph = CreateDataGraph { data.Graph with Graph=dataGraph; DataModel=model }
    { dbase with Graph=graph; Schema=schema; Data=model }